#pragma once
#include <compl.h>
#include <metalc/base/libapds_in.h>
/* mtls */
#include <dinfra/pobj.h>
#include <dinfra/mplf/tstack.h>

#include <metalc/base/mreq.h>

typedef void mlobj_t;
typedef struct mtls{
	apdstls_t	apdstls; /* 必要的信息 */
	mlobj_t		*objs[]; /* 每层私有层级对象数组 */
} mtls_t;


SAI mtls_t *mtls_get();
SAI mtls_t **mtls_getp();

/* 如果没获得成功则会初始化 */
/* 这个最好不要inline */
SAI RETURN_NONULL mtls_t *mtls_get_init();

SAI RETURN_NONULL mtls_t *mtls_by_req(mreq_t *req){
	mtls_t *ret = (mtls_t *)req->tls;
	if (ret) return ret;
	ret = mtls_get_init();
	req->tls = ret;
	return ret;
}

SAI RETURN_NONULL void *mtls_lobj(mtls_t *tls, size_t lidx){
	return tls->objs[lidx];
}

SAI void mtls_freetls(tstack_t *tlstk, mtls_t *p){
	// 挂到链表里
	tstack_push(tlstk, &(p->apdstls.node));
}

// // 由用户申请和释放
SAI mtls_t *mtls_init(void *ptr, size_t size, cid_t tid, cid_t cid){
	ASSERT(ptr);
	mtls_t *mtls = (mtls_t *)ptr;
	/* 先初始化apds */
	PARAM_USED(size);
	_apdstls_init(&mtls->apdstls, sizeof(apdstls_t), tid, cid);

	/* 注册由各层级完成? */
	return mtls;
}


SAI mtls_t *mtls_tryalloctls(tstack_t *tlstk){
	tsnode_t *nd = tstack_pop(tlstk);
	if (!nd) return NULL;
	mtls_t *l = tstack_entry(nd, mtls_t, apdstls.node);
	return l;
}

#ifdef METALC_DYNLIB
static void __thread_initializer();
static void reg_thread_destructor();
SAI void mtls_threadinitializer(bool_t full_init){
	if (full_init) __thread_initializer();
	else reg_thread_destructor();
}
#else
SAI void mtls_threadinitializer(bool_t full_init){
	PARAM_USED(full_init);
}
#endif


/* 从本地上获取私有内存 */
SAI void *mtls_palloc(size_t size);

/* 定义apds_getalloc和ret_locknode*/
// SAI void *get_locknode(const size_t size){ void *ret = pslab_alloc(&(mtls_get()->pslab_ctl), size); ASSUME(ret); return ret;};
// SAI void ret_locknode(void *locknode, const size_t size){ pslab_free(&(mtls_get()->pslab_ctl), locknode); }

/* 问题是tls对象使用时会触发分配 */

/* 在mlcc中使用的锁不能递归 */
#ifndef __linux__
	#warning "[mtls] not linux, may failed when access tls"
#endif

/* lobjnr */
#define DEF_MTLS_PTHREAD(lobjnr, cidupd_freq, oalloc, get_coreid)\
static TLS_INITIAL mtls_t *this_mtls;\
static tstack_packed_t tlstk;\
HIDDEN cid_t __max_threads;\
SAI RETURN_NONULL apdstinfo_t *apdstls_get() {return &this_mtls->apdstls.tinfo;}\
SAI void apdstls_upd(){ _apdstls_updcid(&this_mtls->apdstls, cidupd_freq, get_coreid); }\
CFLOWFIN_FUNC(mtls) { INFO("[%u]mtls thread fin\n",this_mtls->apdstls.tinfo.tid); ASSERT(this_mtls); mtls_freetls((tstack_t *)&tlstk, this_mtls); }\
SYSINIT_FUNC(mtls){\
	INFO("mtls proc init\n");\
	/* mtls_threadinit();*/ \
}\
CFLOWINIT_FUNC(mtls){\
	if (LIKELY(this_mtls)) return; /* 防止so库执行路径重复进入 */ 			\
	mtls_t  *p = mtls_tryalloctls((tstack_t *)&tlstk);						\
	if (UNLIKELY(!p)) {		/* fprintf(stderr, "init?\n"); */		\
		size_t tsize = align_up(sizeof(mtls_t) + lobjnr * sizeof(void *), HDEF_CACHE_LINE_BYTES);\
		void *ptr = oalloc(tsize);						\
		/* if (!ptr) fatal("no memspace for mtls\n"); */			\
		p = mtls_init(ptr, tsize, faa(&__max_threads, 1), 0);			\
		this_mtls = p;\
		INFO("[%u]mtls thread init\n", p->apdstls.tinfo.tid);\
		/* 如果未初始化调用这个 */\
		mtls_threadinitializer(1);			\
		/* fprintf(stderr, "p is %p,  ptr %p, size %lu\n", p, ptr, tsize);*/	\
	}\
	else{ INFO("[%u]mtls reclaim thread init\n",p->apdstls.tinfo.tid); mtls_threadinitializer(0); }\
	this_mtls = p;\
	/* _apdstls_updcid(&p->apdstls, cidupd_freq, get_coreid); */				\
	p->apdstls.cid_updcnt = 0;/* 一开始执行时还是需要获得一次 */			\
}\
SAI RETURN_NONULL mtls_t *mtls_get(){ return this_mtls; /* 返回值一定是非空的 */}\
SAI mtls_t **mtls_getp(){ return &this_mtls; }\
SAI RETURN_NONULL mtls_t *mtls_get_init() { /* 未初始化则只走一便mtls初始化流程*/ if (UNLIKELY(!this_mtls)) _mtls_cflowinit(); return this_mtls; } 

/* 初始化过程优先allocator */
/* 把单线程堆先初始化 */

/* 怎么让线程只初始化一次?? */